/*
 * BlogView.cpp
 *
 *  Created on: 5.11.2009
 *      Author: thyv
 */

#include <QDebug>
#include <QMessageBox>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QStackedWidget>
#include <QFileSystemModel>
#include <QDesktopWidget>
#include <QResizeEvent>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsLinearLayout>
#include <QLabel>
#include <QGraphicsProxyWidget>

#ifdef Q_OS_SYMBIAN
#include <aknappui.h>
#include <avkon.rsg>
#include <aknutils.h>
#endif

#include "busyindicator.h"
#include "setupblog.h"
#include "BlogSetupView.h"
#include "BlogView.h"
#include "wppostgraphicslist.h"
#include "wppagegraphicslist.h"
#include "wpcommentgraphicslist.h"
#include "addpostview.h"
#include "SinglePostView.h"
#include "CategoryView.h"
#include "writepageview.h"
#include "WPNetworkEngine.h"
#include "MediaSelectionList.h"
#include "ProgressDialog.h"
#include "DialogController.h"
#include "statisticsview.h"
#include "wptabbedlistview.h"
#include "wpgraphicsview.h"
#include "enume/pannableview.h"
#include "wptitlebar.h"
#include "wpmenubar.h"
#include "version.h"
#include "scopedtracer.h"
#include "wpconfirmdialog.h"
#include "utils.h"

#include "ScopedTimer.h"

BlogView::BlogView()
  : iCurrentLayoutType(Invalid) // invalid value
  , iSetupBlogView(*this, &BlogView::InitSetupBlogView)
  , iWritePageView(*this, &BlogView::InitWritePageView)
  , iAddPostView(*this, &BlogView::InitAddPostView)
  , iSinglePostView(*this, &BlogView::InitSinglePostView)
  , iCategoryView(*this, &BlogView::InitCategoryView)
  , iStatisticsView(*this, &BlogView::InitStatisticsView)
  , iMediaSelectionView(NULL)
  , iBlogsView(*this, &BlogView::InitBlogsView)
  , iBlogsGraphicsWidget(*this, &BlogView::InitBlogsView)
  , iPannableBlogWidget(*this, &BlogView::InitBlogsView)
  , iNetworkEngine(NULL)
  , iCurrentView(1337)         // XXX: this value is arbitrary, since the initial view is undefined
{
    // Workaround for issue of starting the app in landscape mode.
    // See the resizeEvent for more.
  /*#ifdef Q_WS_MAEMO_5
    setAttribute(Qt::WA_Maemo5StackedWindow);
    setAttribute(Qt::WA_Maemo5LandscapeOrientation, true);
    #endif*/
    iLandscapeSizeWorkaround = false;
    iBusyIndicator = NULL;
    iTabbedListView = NULL;
    iNetworkEngine = NULL;
    iThemeData = NULL;

    // ThemeData stores common brushes and pixmaps so that
    // they don't have to be kept in memory by each object separately
    //
    iThemeData = new ThemeData;
    iThemeData->Init();
    iDialogController = new DialogController(this);

    // XXX: remove
    iViewTitle << tr("Edit blog")
            << tr("Blogs")
            << tr("Edit page")
            << tr("Edit post")
            << tr("Post")
            << tr("Categories")
            << tr("Statistics")
            << tr("WordPress")
            << tr("Images");

    // busy indicator spinner
    iBusyIndicator = new BusyIndicator(this);

/* Main layout */    
    // the fullscreen view, all the visible elements are added to this as a layout
    // XXX: this could just be this, but QMainWindow doesn't really apply...
    iLayoutWidget = new QWidget();
    iLayoutWidget->setObjectName("layoutWidget");

    // main view widgets
    iTitleBar = new WPTitleBar(this, "Wordpress", iBusyIndicator); 
    iStackedWidget = new QStackedWidget(this);
    iMenu = new WPMenu(this);
    
    /* Data model, needs to be constructed before list views. */
    iNetworkEngine = new WPNetworkEngine();
    iBlogs = new WPDataUsersBlogs(iNetworkEngine);
    iGravatars = new WPDataGravatars(iNetworkEngine);
    
/* Tabbed list view */
    iTabbedListView = new WPTabbedListView(this);    

/* Main content */
    iStackedWidget->insertWidget(ETabbedListView, iTabbedListView);
    iStackedWidget->setContentsMargins(0, 0, 0, 0);

/* Data signals */   
    // general data events
    // XXX: these never show up from LoadLocalData()
    connect(
        iBlogs,           SIGNAL(DataError(const QString&)), 
        iDialogController,  SLOT(ShowErrorNote(const QString&))
    );

    // Continue from blog setup screen to main view once the blog has been loaded
    connect(
        iBlogs, SIGNAL(GetUserBlogsCompleted(const WPDataBlog&)), 
        this,     SLOT(ShowTabbedListView())
    );

    // this uses dialog controller
    connect(iNetworkEngine, SIGNAL(NoAccessPoints()), this, SLOT(ShowNoAccessPointWarning()));

    // Progress dialog
    connect(
        iNetworkEngine, SIGNAL(TaskStarted(TWPNetworkEngineCommand)),
        iDialogController, SLOT(TaskStarted(TWPNetworkEngineCommand))
    );

    connect(
        iNetworkEngine, SIGNAL(TaskFinished(TWPNetworkEngineCommand)), 
        iDialogController, SLOT(TaskFinished(TWPNetworkEngineCommand))
    );

    connect(
        iNetworkEngine, SIGNAL(TaskFailed (TWPNetworkEngineCommand, QString)),
        iDialogController, SLOT(TaskFailed (TWPNetworkEngineCommand, QString))
    );

    connect(
        iTitleBar,        SIGNAL(spinnerClicked ()),
        iDialogController,  SLOT(ShowTaskProgress())
    );

    // XXX: better triggering
    connect(
        iNetworkEngine, SIGNAL(UpdateStats(const WPDataStats &)),
        this,             SLOT(ShowStatisticsView())
    );

    // data changed, update views
    connect(
        iBlogs,         SIGNAL(UpdatePageDataFull(const WPDataBlog &)), 
        iTabbedListView->iPagesView,    SLOT(UpdatePageData(const WPDataBlog &))
    );

    connect(
        iBlogs,         SIGNAL(UpdatePostDataFull(const WPDataBlog &)), 
        iTabbedListView->iPostsView,    SLOT(UpdatePostData(const WPDataBlog &))
    );

    connect(
        iBlogs,         SIGNAL(UpdateCommentDataFull(const WPDataBlog &)),
        iTabbedListView->iCommentsView, SLOT(UpdateCommentsData(const WPDataBlog &))
    );

    
    /* XXX:
    connect(
        iBlogs,         SIGNAL(UpdateCommentsData(const WPDataBlog&)), 
        iPostsView,       SLOT(UpdateCommentsData(const WPDataBlog&))
    );
    */

    // XXX: UpdateCommentsDataLight -> iPostsView?

/* UI Signals */    
    // Menu
    connect(
        iMenu,      SIGNAL(exitApplication()),
        this,         SLOT(close())
    );

    // Connect page view context menu signals
    connect(
        iTabbedListView->iPagesView, SIGNAL(OpenClicked(WPPage)), 
        this, SLOT(ShowEditPageView(WPPage))
    );
    connect(
        iTabbedListView->iPagesView, SIGNAL(EditClicked(WPPage)), 
        this, SLOT(ShowEditPageView(WPPage))
    );

    // Connect post view context menu signals
    connect(
        iTabbedListView->iPostsView, SIGNAL(OpenClicked(WPPost)), 
        this, SLOT(ShowSinglePostView(WPPost))
    );
    connect(
        iTabbedListView->iPostsView, SIGNAL(EditClicked(WPPost)), 
        this, SLOT(ShowEditPostView(WPPost))
    );
    connect(
        iTabbedListView->iPostsView, SIGNAL(DeleteClicked(WPPost)), 
        this, SLOT(DeletePost(WPPost))
    );
    
            
    // setup menu
    InitMenuItems();
    
    // set initial layout based on current orientation
    SetAutoLayout();
   
    // try and load locally persisted settings/data
    // Note: triggers refresh if loaded
    if (iBlogs->LoadLocalData()) {
        // show cached data, while we refresh it in the background
        ShowTabbedListView();

    } else {
        // set up initial blog
        ShowInitialSetupBlogView();
    }

#ifdef Q_WS_MAEMO_5
    // we support auto-orientation
     setAttribute(Qt::WA_Maemo5AutoOrientation, true);

#endif
     
     // XXX For some reason focus doesn't work in blog list if
     // it is lazily inited...
     InitBlogsView();
}

BlogView::~BlogView()
{
    delete iThemeData;

    if (iBlogs)
        iBlogs->SaveLocalData();

    delete iGravatars;
    delete iBlogs;
    delete iNetworkEngine;
}

void BlogView::keyPressEvent ( QKeyEvent * event  )
{
    if (event->key() == Qt::Key_Context1 )
    {
        if(iMenu->ActivateSoftkeyAction(WPMenu::PositiveSoftkey))
            event->accept();
    }
    else if(event->key() == Qt::Key_Select)
    {
        if(iMenu->ActivateSoftkeyAction(WPMenu::SelectSoftkey))
            event->accept();
    }
    else if(event->key() == Qt::Key_Context2)
    {
        if(iMenu->ActivateSoftkeyAction(WPMenu::NegativeSoftkey))
            event->accept();
    }
    else if ((event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) &&
             centralWidget() == iLayoutWidget && iStackedWidget->currentWidget() == iTabbedListView 
            )
    {
        // Workaround for issues with using setFocus in comments view
        // while loading data. See wpcommmentsgraphicslist.cpp for details
        iTabbedListView->setFocus();
    }
    else
    {
        QMainWindow::keyPressEvent(event);
    }
}

void BlogView::InitMenuItems ()
{
    // create new QActions for the menu items, and connect them
    connect(
        iMenu->addMenuItem(new QAction(tr("Blogs"), this)), SIGNAL(triggered()),
        this, SLOT(ShowBlogsView())
    );

    connect(
        iMenu->addMenuItem(new QAction(tr("New post"), this)), SIGNAL(triggered()), 
        this, SLOT(ShowWriteNewPostView())
    );
    
    connect(
        iMenu->addMenuItem(new QAction(tr("New page"), this)), SIGNAL(triggered()),
        this, SLOT(ShowWriteNewPageView())
    );

    connect(
        iMenu->addMenuItem(new QAction(tr("Statistics"), this)), SIGNAL(triggered()), 
        this, SLOT(OpenStatisticsView())
    );

    connect(
        iMenu->addMenuItem(new QAction(tr("Refresh"), this)), SIGNAL(triggered()), 
        this, SLOT(Refresh())
    );

    connect(
        iMenu->addMenuItem(new QAction(tr("About"), this)), SIGNAL(triggered()), 
        this, SLOT(About())
    );

    connect(
        iMenu->addMenuItem(new QAction(tr("Exit"), this)), SIGNAL(triggered()), 
        this, SLOT(close())
    );
}

void BlogView::ShowInWindow (QWidget *window)
{
    setCentralWidget(window);
}

void BlogView::ShowInLayout (QWidget *view)
{
    ShowInWindow(iLayoutWidget);

    iStackedWidget->setCurrentWidget(view);
}

void BlogView::SetLayout (LayoutType layoutType)
{
    if (layoutType == iCurrentLayoutType) 
        // no change
        return;

    // remove current layout
    QLayout *layout = iLayoutWidget->layout();

    // clear
    while (layout && !layout->isEmpty())
        layout->removeItem(layout->itemAt(0));

    // drop
    delete layout;
    
    // set new type
    iCurrentLayoutType = layoutType;

    switch (layoutType) {
        case Portrait:
        case LandscapeMenuAtBottom: {
            QGridLayout *portraitLayout = new QGridLayout();

            portraitLayout->addWidget(iTitleBar,      0, 0, 1, 1);
            portraitLayout->addWidget(iStackedWidget, 1, 0, 1, 1);
            portraitLayout->addWidget(iMenu,          2, 0, 1, 1);
            
            // row
            iMenu->setOrientation(Qt::Horizontal);
            
            layout = portraitLayout;

        } break;

        case Landscape: {
            QGridLayout *landscapeLayout = new QGridLayout();

            landscapeLayout->addWidget(iTitleBar,      0, 0, 1, 1);
            landscapeLayout->addWidget(iStackedWidget, 1, 0, 1, 1);
            landscapeLayout->addWidget(iMenu,          0, 1, 2, 1);

            // column
            iMenu->setOrientation(Qt::Vertical);

            layout = landscapeLayout;

        } break;

        case Invalid: {
            // XXX: faaail
            Q_ASSERT(false);
        }
    }

    // set new layout
    layout->setSpacing(0);
    layout->setContentsMargins(0, 0, 0, 0);

    iLayoutWidget->setLayout(layout);
}
    
void BlogView::SetAutoLayout ()
{
    // determine layout using just our top-level window's dimensions, not the desktop's
    QSize window = size();
    
    // auto-orient
    if (window.width() < window.height())
        // tall
        SetLayout(Portrait);

    else
        {
        // wide
#ifdef Q_OS_SYMBIAN
        if(AknLayoutUtils::CbaLocation() == AknLayoutUtils::EAknCbaLocationRight)
            SetLayout(Landscape);
        else
            SetLayout(LandscapeMenuAtBottom);
#else 
        SetLayout(Landscape);    
#endif // Q_OS_SYMBIAN
        }
}

void BlogView::resizeEvent (QResizeEvent *e)
{
    ScopedTracer tracer("WP::BlogView::resizeEvent ");
    tracer << e->size();
    
    QMainWindow::resizeEvent(e);

    // switch layout if needed
    SetAutoLayout();
    

/* XXX: other stuff, needed?

    // Workaround for landscape mode height exceeding the available height.
    // The pixel amount is hardcoded, found out manually.
    // TODO If a Qt fix becomes available, disable this.
    if (!iLandscapeSizeWorkaround)
    {
        // The maximum height is only set in the first resize event in landscape mode.
        // This seems to be the only situation when the application gets the wrong height.
        if (window.width() == 640 && window.height() == 360)
            iStackedWidget->setMaximumHeight(geometry().size().height()); // 29 -- 85
        else if (window.width() == 320 && window.height() == 240)
            iStackedWidget->setMaximumHeight(geometry().size().height()); // 57 -- 107
    }
    else if (iStackedWidget->maximumHeight() < QWIDGETSIZE_MAX)
    {
        // In further resize events, clear all restrictions
        iStackedWidget->setMaximumHeight(QWIDGETSIZE_MAX);
    }

    iLandscapeSizeWorkaround = true;
    e->ignore();
    
    if (iTabScene && iLayoutWidget)
    {
        iLayoutWidget->resize(window.width(),window.height());
        iSetupBlogProxy->setMaximumWidth(window.width());
    }
*/    
}

void BlogView::closeEvent(QCloseEvent *e)
{
    if (WPConfirmDialog::RunDialog(this))
        e->accept();
    else
        e->ignore();
}

/*  
void BlogView::ShowInTab (...)
{
    const int KFirstContentElement = 1;
    const int KOptionalContentElement = 2;

    if (iLayout->itemAt(KFirstContentElement) == aItem)
    {
        // nothing to do
        return;
    }

    // Remove and hide current item(s).
    //
    if (iLayout->itemAt(KFirstContentElement) == iTabBarView)
    {
        // tab content also.
        iLayout->itemAt(KOptionalContentElement)->graphicsItem()->hide();
        iLayout->removeAt(KOptionalContentElement);
    }
    iLayout->itemAt(KFirstContentElement)->graphicsItem()->hide();
    iLayout->removeAt(KFirstContentElement);

    // Add and show new widget(s).
    //
    iLayout->insertItem(KFirstContentElement,aItem);
    aItem->show();
    aItem->setFocus();
    
    if (aItem == iTabBarView)
    {
        iLayout->insertItem(KOptionalContentElement,iTabContentWidget);
        iTabContentWidget->show();
    }
}
*/    

void BlogView::SwitchView(TMainView view)
{
    // Change the view
    //
    switch (view)
    {
#ifdef XX_Q_WS_MAEMO_5
    case EInitialSetupBlogView:
        // fullscreen widget
        ShowInWindow(iInitialSetupBlogView);
        
        break;
#endif

    case EStatisticsView:
        ShowInLayout(iStatisticsView);

        // XXX:
        iTitleBar->setText("Statistics");

        iMenu->showBack(iStatisticsView->closeAction());

        break;

    case ECategoryView:
        ShowInLayout(iCategoryView);

        iTitleBar->setText(iCategoryView->TitleText());

        iMenu->showSaveCancel(iCategoryView->HappyAction(), iCategoryView->SadAction());

        break;

    case EMediaSelectionView:
        ShowInLayout(iMediaSelectionView);

        iTitleBar->setText(iMediaSelectionView->TitleText());

        iMenu->showSaveCancel(iMediaSelectionView->HappyAction(), iMediaSelectionView->SadAction());

        break;

    case EBlogsView:
        ShowInLayout(iBlogsView);
        iBlogsGraphicsWidget->setFocus();

        iTitleBar->setText(tr("Blogs"));

        iMenu->showBack(iBlogsGraphicsWidget->CloseAction());

        break;

    case ESinglePostView:
        ShowInLayout(iSinglePostView);

        iTitleBar->setText(iSinglePostView->TitleText());

        iMenu->showBack(iSinglePostView->SadAction());

        break;

    case ESetupBlogView:
        ShowInLayout(iSetupBlogView);

        iTitleBar->setText(iSetupBlogView->TitleText());

        if(iBlogs->GetBlogCount() == 0) {
            iMenu->showSaveExit(iSetupBlogView->HappyAction());
        } else {
            iMenu->showSaveCancel(iSetupBlogView->HappyAction(), iSetupBlogView->SadAction());
        }
        
        break;

    case EWritePageView:
        ShowInLayout(iWritePageView);

        iTitleBar->setText(iWritePageView->TitleText());

        iMenu->showSaveCancel(iWritePageView->HappyAction(), iWritePageView->SadAction());

        break;

    case EAddPostView:
        ShowInLayout(iAddPostView);

        iTitleBar->setText(iAddPostView->TitleText());

        iMenu->showSaveCancel(iAddPostView->HappyAction(), iAddPostView->SadAction());
        
        break;

    case ETabbedListView:
        {
        ShowInLayout(iTabbedListView);

        // XXX: what does this actually do?
        iTabbedListView->switchPreviousWidget();
        
        QString text = iBlogs->GetCurrentBlog() ? iBlogs->GetCurrentBlog()->iBlogName : tr("WordPress");
        text = Utils::toDisplayHtml(text);
        iTitleBar->setText(text);

        iMenu->showMenuQuit();

        break;
        }

    case ENoView:
        // Do nothing
        break;
    }

    // XXX: fix to same as iTitleBar!!
    setWindowTitle(iViewTitle.at(view));

    iCurrentView = view;

    // give focus
    SetActiveView();
}
 
void BlogView::ShowTabbedListView ()
{
    SwitchView(ETabbedListView);
}
   
void BlogView::ShowInitialSetupBlogView ()
{
#ifdef XX_Q_WS_MAEMO_5
    // fullscreen
    SwitchView(EInitialSetupBlogView);
#else
    // in layout
    SwitchView(ESetupBlogView);
#endif          
}

void BlogView::ShowEditPageView(WPPage aPage)
{
    iWritePageView->EditPage(*iBlogs->GetCurrentBlog(), aPage);
    SwitchView(EWritePageView);
}

void BlogView::ShowWriteNewPageView()
{
    iWritePageView->NewPage(*iBlogs->GetCurrentBlog());
    SwitchView(EWritePageView);
}

void BlogView::ShowSinglePostView(WPPost post)
{
    qDebug("WP::BlogView::ShowSinglePostView()");
    
    iSinglePostView->ShowPost(*iBlogs->GetCurrentBlog(), post);
    SwitchView(ESinglePostView);
}

void BlogView::ShowEditPostView(WPPost post)
{
    qDebug("WP::BlogView::ShowEditPostView()");
    iAddPostView->EditPost(iBlogs->GetCurrentBlog(), post);
    SwitchView(EAddPostView);
}

void BlogView::ShowWriteNewPostView()
{
    iAddPostView->NewPost(iBlogs->GetCurrentBlog());
    SwitchView(EAddPostView);
}

void BlogView::ShowBlogsView()
{
    // Update data so that latest activity is shown correctly
    iBlogsGraphicsWidget->UpdateData(*iBlogs);
    SwitchView(EBlogsView);
}

void BlogView::ShowNewBlogView()
{
    iSetupBlogView->NewBlog();
    SwitchView(ESetupBlogView);
}

void BlogView::ShowEditBlogView(const QString& aBlogId)
{
    iSetupBlogView->EditBlog(iBlogs->GetBlog(aBlogId));
    SwitchView(ESetupBlogView);
}

void BlogView::OpenStatisticsView ()
{
    WPDataBlog *blog = iBlogs->GetCurrentBlog();

    if (!blog)
        return;

    // ensure that blog is wordpress.com hosted and we have an API key
    if (blog->isWordpressHosted() && blog->HasApiKey()) {
        // load data using existing key
        blog->RefreshStats();

        // show progress
        iDialogController->ShowTaskProgress();

    } else {
        iDialogController->ShowInfoNote(tr("Statistics"), tr("Statistics are available for wordpress.com hosted blogs only."));
        return;
    }

    // do we have some existing stats to show right away?
    if (blog->HasStatsData()) {
        // show stats as they load
        iStatisticsView->updateStats(blog->iStats);
        ShowStatisticsView();

    } else {
        // wait for the initial data to load before showing the stats view
        // we're most likely to get errors here, and we don't need to show the stats view at all
        // in those cases

    }
}

void BlogView::ShowStatisticsView ()
{
    SwitchView(EStatisticsView);
}

void BlogView::SaveBlogSetup(WPDataBlog *blog, const WPNetworkEndpoint &settings)
{
    // show progress for this
    //iDialogController->ShowTaskProgress();

    if (blog)
        iBlogs->EditBlog(blog, settings);
    else
        iBlogs->NewBlog(settings);
}

void BlogView::DeletePost(WPPost post)
{
    qDebug("WP::BlogView::DeletePost()");

    post->Delete();
}

void BlogView::OpenBlog(const QString& aBlogId)
{
    // show progress for this
    //iDialogController->ShowTaskProgress();

    iBlogs->OpenBlog(iBlogs->GetBlog(aBlogId));

    ShowTabbedListView();
}

bool BlogView::DeleteBlog(const QString& aBlogId)
{
    bool ret = iBlogs->DeleteBlog(iBlogs->GetBlog(aBlogId));
    if(iBlogs->GetBlogCount() == 0) {
        ShowNewBlogView();
    }
    return ret;
}

void BlogView::ShowCategoryView(const QStringList &categories)
{
    iCategoryView->SelectCategories(categories);

    SwitchView(ECategoryView);
}

void BlogView::CategoriesSelected (const QStringList &categories)
{
    iAddPostView->SelectCategories(categories);

    // return
    SwitchView(EAddPostView);
}
    
void BlogView::CategorySelectionCancelled ()
{
    // return
    SwitchView(EAddPostView);
}

void BlogView::ShowImageList(const QStringList& aInitialSelections, bool aPostView)
{
    ShowMediaList(aInitialSelections, aPostView, MediaSelectionList::Images);
}

void BlogView::ShowVideoList(const QStringList& aInitialSelections, bool aPostView)
{
    if(!iUiData.videoNoteHasBeenShown()) {
        iDialogController->ShowInfoNote(
                tr("Video upload"),
                tr("Uploading video requires using VideoPress, or configuring your blog manually.")
                );
        iUiData.setVideoNoteShown();
    }
    ShowMediaList(aInitialSelections, aPostView, MediaSelectionList::Videos);
}


void BlogView::ShowMediaList(const QStringList& aInitialSelections, bool aPostView, int type)
{
    iAddMediaToPosts = aPostView;

    MediaSelectionList::MediaType castedType = static_cast<MediaSelectionList::MediaType>(type);
    iMediaSelectionView = new MediaSelectionList(aInitialSelections, castedType, this);
    iStackedWidget->insertWidget(EMediaSelectionView, iMediaSelectionView);
    
    connect(iMediaSelectionView, SIGNAL(SearchComplete()), this, SLOT(ReallyShowMediaList()));
    connect(iMediaSelectionView, SIGNAL(SearchCanceled()), this, SLOT(CancelShowMediaList()));
    
    switch(type) {
        case MediaSelectionList::Images:
            connect(iMediaSelectionView, SIGNAL(ImagesSelected(const QStringList&,const QList<QPixmap>&)), this, SLOT(ImagesSelected(const QStringList&,const QList<QPixmap>&)));
            break;
        case MediaSelectionList::Videos:
            connect(iMediaSelectionView, SIGNAL(VideosSelected(const QStringList&)), this, SLOT(VideosSelected(const QStringList&)));
            break;
    }

    // signals
    connect(
            iMediaSelectionView, SIGNAL(TaskStarted(TWPNetworkEngineCommand)), 
            iDialogController, SLOT(TaskStarted(TWPNetworkEngineCommand)));

    connect(
            iMediaSelectionView, SIGNAL(TaskFinished(TWPNetworkEngineCommand)), 
            iDialogController, SLOT(TaskFinished(TWPNetworkEngineCommand))
    );

    // Call this only after the connections so that we can show a progess dialog
    iMediaSelectionView->SearchMedia();
}

void BlogView::ReallyShowMediaList()
{
    SwitchView(EMediaSelectionView);
}

void BlogView::CancelShowMediaList()
{
    iStackedWidget->removeWidget(iMediaSelectionView);
    iMediaSelectionView->deleteLater();
}

void BlogView::ShowNoAccessPointWarning()
{
    iDialogController->ShowErrorNote(tr("No usable access point found. Please set up an access point and try again."));
}

void BlogView::ImagesSelected(const QStringList& aFilenames, const QList<QPixmap>& aThumbnails)
{
    if (iAddMediaToPosts)
        iAddPostView->ImagesAdded(aFilenames, aThumbnails);
    else
        iWritePageView->ImagesAdded(aFilenames, aThumbnails);
    
    MediaSelected();
}

void BlogView::VideosSelected(const QStringList& aFilenames)
{
    if (iAddMediaToPosts)
        iAddPostView->VideosAdded(aFilenames);
    else
        iWritePageView->VideosAdded(aFilenames);
    
    MediaSelected();
}

void BlogView::MediaSelected()
{
    // clear
    iStackedWidget->removeWidget(iMediaSelectionView);
    iMediaSelectionView->deleteLater();

    // return
    if (iAddMediaToPosts)
        SwitchView(EAddPostView);
    else
        SwitchView(EWritePageView);
}

void BlogView::AddNewComment(WPPost aPost, const QString& aBody)
{
    aPost->NewComment(aBody);

    SwitchView(ESinglePostView);
}

void BlogView::ReplyToComment(WPComment aComment)
{
    WPDataBlog *blog = iBlogs->GetCurrentBlog();

    WPPost post = blog->iPosts.GetByItemId(aComment->iPostId);

    if (post) {
        iSinglePostView->ShowPost(*blog, post);
        iSinglePostView->ScrollToReplyField();
        SwitchView(ESinglePostView);
    }
}

void BlogView::About()
{
    // TODO add an icon
#ifdef Q_WS_MAEMO_5
    QString about("Nokia WordPress version ");
#else
    QString about("Nokia WordPress\nversion ");
#endif
    about.append(WP_VERSION_STR);
    iDialogController->ShowInfoNote("About", about);
}

void BlogView::Refresh()
{
    // show progress dialog
    //iDialogController->ShowTaskProgress();
    iBlogs->RefreshCurrentBlog();
}

/**
 * Sets the active view after ProgressDialog closes. 
 */
void BlogView::SetActiveView(BlogView::TMainView aRefocusableView)
{
  //#ifndef Q_WS_MAEMO_5
    // Update focus if
    //   a) there is an active view AND
    //   b) either the call is general, or a specific view wants its focus
    //      to be updated in case it is the current view (separate views do
    //      not know if they are active at a given time or not).
    if  (iStackedWidget->currentWidget() && 
         (aRefocusableView == BlogView::ENoView || aRefocusableView == iCurrentView))
    {
        // TODO non-virtual setFocus calls base class function if called from
        // QWidget* -- create some Focusable interface to fix this? For now,
        // call separately for each view that has special focus function.
        switch (iCurrentView)
        {
            case ETabbedListView:
                iTabbedListView->setFocus();
                break;
            case ECategoryView:
                iCategoryView->setFocus();
                break;
            case ESetupBlogView:
                iSetupBlogView->setFocus();
                break;
            case EBlogsView:
                iBlogsView->setFocus();
                break;
            case EAddPostView:
                iAddPostView->setFocus();
                break;
            case EWritePageView:
                iWritePageView->setFocus();
                break;
            case EMediaSelectionView:
                iMediaSelectionView->setFocus();
                break;
            case EStatisticsView:
                iStatisticsView->setFocus();
                break;
            default:
                iStackedWidget->currentWidget()->setFocus();
                break;
        }

        // After calling setFocus, the options menu receives an extra "Actions" item.
        // It's not BlogView, it's not currentView. We'll get around it for now
        // by disabling context menu in all widgets.
        QList<QWidget*> list = QApplication::allWidgets();
        const int count = list.count();
        for (int i = 0; i < count; i++)
        {
            list[i]->setContextMenuPolicy(Qt::NoContextMenu);
        }
    }
    //#endif
}

void BlogView::ActivateBusyIndicator() 
{ 
    iBusyIndicator->Activate();
}
void BlogView::DeactivateBusyIndicator() 
{ 
    iBusyIndicator->Deactivate(); 
}

BusyIndicator& BlogView::GetBusyIndicator()
{
    return *iBusyIndicator;
}

void BlogView::InitSetupBlogView()
{
    iSetupBlogView = new SetupBlog(this);
    iStackedWidget->insertWidget(ESetupBlogView, iSetupBlogView);

    connect(
            iSetupBlogView, SIGNAL(ErrorNote(QString)),
            iDialogController, SLOT(ShowErrorNote(QString))
    );
}

void BlogView::InitWritePageView()
{
    iWritePageView = new WritePageView(this);
    iStackedWidget->insertWidget(EWritePageView, iWritePageView);
    connect(
        iWritePageView, SIGNAL(ShowErrorNote(const QString&)), 
        iDialogController, SLOT(ShowErrorNote(const QString&))
    );
    connect(
        iWritePageView, SIGNAL(ShowWarningNote(const QString&)),
        iDialogController, SLOT(ShowWarningNote(const QString&))
    );
}

void BlogView::InitAddPostView()
{
    iAddPostView = new AddPostView(this);
    iStackedWidget->insertWidget(EAddPostView, iAddPostView);
    connect(
        iAddPostView, SIGNAL(ShowErrorNote(const QString&)), 
        iDialogController, SLOT(ShowErrorNote(const QString&))
    );
    connect(
        iAddPostView, SIGNAL(ShowWarningNote(const QString&)),
        iDialogController, SLOT(ShowWarningNote(const QString&))
    );
    connect(
        iAddPostView, SIGNAL(ResolveFormattedAddress(qreal, qreal)),
        iNetworkEngine, SLOT(GetLocationAddress(qreal,qreal))
    );
    connect(
        iNetworkEngine, SIGNAL(FormattedAddressGotten(qreal,qreal,QString)),
        iAddPostView, SLOT(FormattedAddressResolved(qreal,qreal,QString))
    );
}

void BlogView::InitSinglePostView()
{
    iSinglePostView = new SinglePostView(*this);
    iStackedWidget->insertWidget(ESinglePostView, iSinglePostView);
    
    // SinglePostView has both post and comments
    connect(
        iBlogs,         SIGNAL(UpdatePostData(const WPDataBlog &)), 
        iSinglePostView,  SLOT(UpdateData(const WPDataBlog &))
    );

    connect(
        iBlogs,         SIGNAL(UpdateCommentDataFull(const WPDataBlog &)), 
        iSinglePostView,  SLOT(UpdateData(const WPDataBlog &))
    );
}

void BlogView::InitCategoryView()
{
    iCategoryView = new CategoryView(this);
    iStackedWidget->insertWidget(ECategoryView, iCategoryView);
    connect(
        iBlogs,         SIGNAL(UpdateCategoryData (const WPDataBlog &)),
        iCategoryView,    SLOT(UpdateCategoryData (const WPDataBlog &))
    );
        
    connect(
        iCategoryView,  SIGNAL(SelectionDone (const QStringList &)),
        this,             SLOT(CategoriesSelected (const QStringList &))
    );

    connect(
        iCategoryView,  SIGNAL(SelectionCancelled ()),
        this,             SLOT(CategorySelectionCancelled ())
    );
    
    if(iBlogs->GetCurrentBlog())
        iCategoryView->UpdateCategoryData(*iBlogs->GetCurrentBlog());
}

void BlogView::InitStatisticsView()
{
    iStatisticsView = new StatisticsView(this);
    iStackedWidget->insertWidget(EStatisticsView, iStatisticsView);
    connect(
        iNetworkEngine, SIGNAL(UpdateStats(const WPDataStats &)), 
        iStatisticsView,  SLOT(updateStats(const WPDataStats &))
    );
    
    if(iBlogs->GetCurrentBlog())
        iStatisticsView->updateStats(iBlogs->GetCurrentBlog()->iStats);
}

void BlogView::InitBlogsView()
{
    iBlogsView = new WPGraphicsView(this);
    iBlogsView->setObjectName("blogListView");
    iBlogsView->setContentsMargins(0, 0, 0, 0);
    iBlogsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    iBlogsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    
    iPannableBlogWidget = new PannableView(Qt::Vertical);
    iBlogsGraphicsWidget = new BlogSetupView(this, *iBlogsView, iPannableBlogWidget);
    iPannableBlogWidget->setWidget(iBlogsGraphicsWidget);
    iBlogsGraphicsWidget->setContentsMargins(0.0, 0.0, 0.0, 0.0);
    
    iPannableBlogWidget->enableScrollIndicator(true);
    iBlogsView->setWidget(iPannableBlogWidget);
    
    iStackedWidget->insertWidget(EBlogsView, iBlogsView);
    
    connect(
        iBlogs,         SIGNAL(UpdateBlogs(const WPDataUsersBlogs &)),
        iBlogsGraphicsWidget, SLOT(UpdateData(const WPDataUsersBlogs &))
    );
    
    if(iBlogs)
        iBlogsGraphicsWidget->UpdateData(*iBlogs);
}
